package com.pkx.cloud.fse7.conf;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import net.logstash.logback.encoder.org.apache.commons.lang.StringUtils;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * @Description
 * @Author chenwg
 * @date 2020.11.04 12:49
 */
@Configuration
public class CustomDateSerializerConfig {

    public static final String YYYY_MM = "yyyy-MM";
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    public static final String MATCHES_YYYY_MM = "^\\d{4}-\\d{1,2}$";
    public static final String MATCHES_YYYY_MM_DD = "^\\d{4}-\\d{1,2}-\\d{1,2}$";
    public static final String MATCHES_YYYY_MM_DD_HH_MM = "^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$";
    public static final String MATCHES_YYYY_MM_DD_HH_MM_SS = "^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$";


    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
        return builder -> {
            // 序列化
            builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer());
            builder.serializerByType(LocalDate.class, new LocalDateSerializer());
            builder.serializerByType(Date.class, new DateSerializer());
            // 反序列化
            builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer());
            builder.deserializerByType(LocalDate.class, new LocalDateDeserializer());
            builder.deserializerByType(Date.class, new DateDeserializer());
        };
    }

    /**
     * LocalDateTime 序列化
     */
    public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException {
            if (value != null) {
                long timestamp = value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                gen.writeNumber(timestamp);
            }
        }
    }

    /**
     * LocalDateTime 反序列化
     */
    public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext)
                throws IOException {
            String valueAsString = p.getValueAsString().trim();
            if (StringUtils.isNumeric(valueAsString)) {
                // 如果是时间戳形式
                return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault());
            } else if (valueAsString.matches(CustomDateSerializerConfig.MATCHES_YYYY_MM_DD_HH_MM_SS)) {
                // 如果是 yyyy-MM-dd HH:mm:ss 形式
                return LocalDateTime.parse(valueAsString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            } else if (valueAsString.matches(CustomDateSerializerConfig.MATCHES_YYYY_MM_DD)) {
                // 如果是 yyyy-MM-dd 形式
                return LocalDateTime.parse(valueAsString, DateTimeFormatter.ISO_LOCAL_DATE);
            } else {
                return null;
            }
        }
    }

    /**
     * Date 序列化
     */
    public static class DateSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            if (value != null) {
                long timestamp = value.getTime();
                gen.writeNumber(timestamp);
            }
        }
    }

    /**
     * Date 反序列化
     */
    public static class DateDeserializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            String valueAsString = p.getValueAsString().trim();
            if (StringUtils.isNumeric(valueAsString)) {
                // 如果是时间戳形式
                return new Date(p.getValueAsLong());
            } else if (valueAsString.matches(CustomDateSerializerConfig.MATCHES_YYYY_MM_DD_HH_MM_SS)) {
                // 如果是 yyyy-MM-dd HH:mm:ss 形式
                return CustomDateSerializerConfig.parseDate(valueAsString, CustomDateSerializerConfig.YYYY_MM_DD_HH_MM_SS);
            } else if (valueAsString.matches(CustomDateSerializerConfig.MATCHES_YYYY_MM_DD)) {
                // 如果是 yyyy-MM-dd 形式
                return CustomDateSerializerConfig.parseDate(valueAsString, CustomDateSerializerConfig.YYYY_MM_DD);
            } else {
                return null;
            }
        }
    }


    /**
     * LocalDate序列化
     */
    public static class LocalDateSerializer extends JsonSerializer<LocalDate> {
        @Override
        public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            if (value != null) {
                long timestamp = value.atStartOfDay(ZoneOffset.ofHours(8)).toInstant().toEpochMilli();
                gen.writeNumber(timestamp);
            }
        }
    }

    /**
     * LocalDate反序列化
     */
    public static class LocalDateDeserializer extends JsonDeserializer<LocalDate> {
        @Override
        public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            String valueAsString = p.getValueAsString().trim();
            if (StringUtils.isNumeric(valueAsString)) {
                // 如果是时间戳形式
                return Instant.ofEpochMilli(p.getValueAsLong()).atZone(ZoneOffset.ofHours(8)).toLocalDate();
            } else if (valueAsString.matches(CustomDateSerializerConfig.MATCHES_YYYY_MM_DD)) {
                // 如果是 yyyy-MM-dd 形式
                return LocalDate.parse(valueAsString, DateTimeFormatter.ISO_LOCAL_DATE);
            } else {
                return null;
            }
        }

    }

    /**
     * 字符串解析成date
     *
     * @param dateStr
     * @param format
     * @return
     */
    public static Date parseDate(String dateStr, String format) {
        Date date;
        try {
            DateFormat dateFormat = new SimpleDateFormat(format);
            date = dateFormat.parse(dateStr);
        } catch (Exception e) {
            throw new IllegalArgumentException(e.getLocalizedMessage());
        }
        return date;
    }
}